/*
 * Copyright 2018-2021 guerlab.net and other contributors.
 *
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.guerlab.smart.pay.web.wx;

import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.extern.slf4j.Slf4j;
import net.guerlab.smart.pay.core.domain.PayLogExtends;
import net.guerlab.smart.pay.service.entity.PayLog;
import net.guerlab.smart.pay.service.service.PayLogService;
import net.guerlab.smart.platform.commons.Constants;
import net.guerlab.smart.platform.commons.ip.IpUtils;
import net.guerlab.smart.wx.auth.WxUserContextHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import javax.servlet.http.HttpServletRequest;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 * 抽象微信支付请求控制器
 *
 * @author guer
 */
@Slf4j
public abstract class AbstractWxPayRequestController extends AbstractWxPayController {

    private PayLogService logService;

    @Operation(description = "通过支付订单ID请求支付", security = @SecurityRequirement(name = Constants.TOKEN))
    @GetMapping("/byPayOrderId/{appId}/{payOrderId}")
    public final Object byPayOrderId(@Parameter(name = "微信应用ID", required = true) @PathVariable String appId, @Parameter(name = "支付订单ID", required = true) @PathVariable Long payOrderId, HttpServletRequest request) {
        PayLog payLog = logService.create(payOrderId, getPayChannel(), createPayLogExtends(appId));
        return pay0(WxUserContextHandler.getOpenId(), appId, payLog, request);
    }

    @Operation(description = "通过业务分组和业务ID请求支付", security = @SecurityRequirement(name = Constants.TOKEN))
    @GetMapping("/byBusinessId/{appId}/{businessGroup}/{businessId}")
    public final Object byBusinessId(@Parameter(name = "微信应用ID", required = true) @PathVariable String appId, @Parameter(name = "业务分组", required = true) @PathVariable String businessGroup,
            @Parameter(name = "业务ID", required = true) @PathVariable String businessId, HttpServletRequest request) {
        PayLog payLog = logService.create(businessGroup, businessId, getPayChannel(), createPayLogExtends(appId));
        return pay0(WxUserContextHandler.getOpenId(), appId, payLog, request);
    }

    private PayLogExtends createPayLogExtends(String appId) {
        PayLogExtends payLogExtends = new PayLogExtends();
        payLogExtends.put(KEY_APP_ID, appId);
        return payLogExtends;
    }

    private <T> T pay0(String openId, String appId, PayLog payLog, HttpServletRequest request) {
        String payLogIdString = Objects.toString(payLog.getPayLogId());

        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setOpenid(openId);
        orderRequest.setProductId(payLogIdString);
        orderRequest.setBody(payLog.getOrderTitle());
        orderRequest.setOutTradeNo(payLogIdString);
        orderRequest.setTotalFee(payLog.getAmount().multiply(WxPayServiceConstant.HUNDRED).intValue());
        orderRequest.setSpbillCreateIp(IpUtils.getIp(request));
        orderRequest.setTimeExpire(payLog.getPayTimeoutTime().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        orderRequest.setNotifyUrl(getNotifyUrl(appId));
        orderRequest.setTradeType(getWxPayServiceType().getTradeType());

        return buildWxPayService(appId, true).createOrder(orderRequest);
    }

    /**
     * 获取通知URL
     *
     * @param appId
     *         应用ID
     * @return 通知URL
     */
    protected abstract String getNotifyUrl(String appId);

    @Autowired
    public void setLogService(PayLogService logService) {
        this.logService = logService;
    }
}
